'''
Created on May 24, 2011

@author: Roni
'''
import graph
import cliques.utils
import logging
from cliques.cliqueFinder import cliqueFinder
from scenario import Scenario
import os.path

class ScenarioGenerator(object):
    '''
    Generates a complete scenario: graph+start node
    '''
    
    def __init__(self, base_folder,graph_generator_method=None):
        '''
        Constructor
        '''
        self.base_folder = base_folder # The folder where to store the generated scenarios
        if os.path.isdir(base_folder)==False:
            os.mkdir(self.base_folder)
        # Initialize the graph generator method
        if graph_generator_method==None:
            self.graph_generator = self.__generate_graph
        else:
            self.graph_generator = graph_generator_method



    def __generate_graph(self,nodes,edge_factor):
        ''' Creates a random graph '''
        new_graph = graph.graph()    
        edges = nodes*edge_factor
        edges = min(edges, nodes*(nodes-1)/2) # Verify that #edges is feasible
        new_graph.generate(nodes, edges)
        return new_graph


    def generate(self, nodes, edge_factor, clique_size):
        ''' Generate a random graph with the given nodes and edges, 
        and with a clique of the given size '''

        exp_graph = self.graph_generator(nodes, edge_factor)
        start_node = cliques.utils.choose_random_node(exp_graph)       
        clique_finder = cliqueFinder()
        clique_finder.setup(exp_graph)
        
        # Check if contains a k-clique is start_node's connected component
        connected_comp = exp_graph.connected_components()
        comp_index = connected_comp[start_node]
        comp_items = [item for item in connected_comp.keys() if connected_comp[item]==comp_index]
        k_clique_exists = clique_finder.has_clique(clique_size, comp_items)
        if k_clique_exists:
            return Scenario(exp_graph, start_node) 
        else:
            return None
    
    # ------------ Methods for storing and loading a scenario ------ #    
    def load(self,nodes,edges,clique_size,iteration):
        return Scenario.load(self.__file_name(nodes, edges, clique_size, iteration))
    
    def store(self,a_scenario,nodes,edges,clique_size,iteration):
        a_scenario.store(self.__file_name(nodes, edges, clique_size, iteration))
                
    def __file_name(self,nodes,edges,clique_size, iteration):
        ''' Set a standard file name for a generated scenario '''
        return os.path.join(self.base_folder,"scenario[n%d,e%d,k%d,i%d]" % (nodes,edges, clique_size,iteration))
        
    def prepare_scenarios(self,node_range, edge_factor_range, clique_size_range,iterations):
        MAX_ATTEMPTS = 100
        for nodes in node_range:
            for edge_factor in edge_factor_range:
                for clique_size in clique_size_range:
                    for iteration in xrange(iterations):
                        for attempt in xrange(MAX_ATTEMPTS):
                            logging.info("Attempt %d to generate scenario(%d,%d,%d,%d)" % (attempt,nodes,edge_factor,clique_size,iteration))
                            a_scenario = self.generate(nodes, edge_factor, clique_size)
                            if a_scenario is not None:
                                logging.info("Generated Scenario(%d,%d,%d,%d)" % (nodes,edge_factor,clique_size,iteration))
                                self.store(a_scenario, nodes, edge_factor, clique_size, iteration)
                                scenario_generated=True
                                break
                            else:
                                logging.info("Failed in Generating Scenario(%d,%d,%d,%d), attempt %d" % (nodes,edge_factor,clique_size,iteration,attempt))
                                scenario_generated=False
                        if scenario_generated==False:
                            logging.info("Failed in Generating Scenario(%d,%d,%d,%d)" % (nodes,edge_factor,clique_size,iteration))
                            break;
                    if scenario_generated==False:
                        logging.info("Failed in Generated Scenario(%d,%d,%d)" % (nodes,edge_factor,clique_size))
                        break;
                
           
        